mod traits;
pub use traits::*;

mod timer;
pub(crate) use timer::*;

#[allow(clippy::module_inception)]
mod event;
pub(crate) use event::*;

mod sched;
pub(crate) use sched::*;

mod waker;
pub(crate) use waker::*;

cfg_if::cfg_if! {
    if #[cfg(any(
            target_os = "linux",
            target_os = "android",
            target_os = "illumos",
            target_os = "redox",
    ))] {
        mod epoll;
        pub(crate) use epoll::*;
    } else if #[cfg(any(
            target_os = "ios",
            target_os = "macos",
            target_os = "freebsd",
            target_os = "openbsd",
            target_os = "netbsd",
            target_os = "dragonfly",
            target_os = "tvos",
            target_os = "watchos",
            ))] {
        mod kqueue;
        pub(crate) use kqueue::*;
    } else {
        mod select;
        pub(crate) use select::*;
    }
}

#[cfg(test)]
mod test {
    use crate::event;
    use crate::event::{Poll, PollEvent, Scheduler};
    use hipool::MemPool;
    #[test]
    fn test_waker() {
        let pool = MemPool::new_boxed(0).unwrap();
        let mut poll = event::PollImpl::new_in(&pool).unwrap();
        let waker = event::Waker::new().unwrap();
        let _ = poll.add_event(waker.fd.fd(), event::POLLIN, 0_u64);
        let mut events = 0;
        let mut n = 0;
        for PollEvent(e, _) in poll.wait(0) {
            events = e;
            n += 1;
        }
        assert_eq!(events, 0);
        assert_eq!(n, 0);
        assert!(!waker.awaken());
        waker.wake();
        n = 0;
        for PollEvent(_, _) in poll.wait(0) {
            n += 1;
        }
        assert_eq!(n, 1);
        assert!(waker.awaken());
    }

    #[test]
    fn test_scheduler() {
        let pool = MemPool::new_boxed(0).unwrap();
        let mut sched = event::SchedImpl::new_in(&*pool).unwrap();
        fn timer_timeout(this: &event::Timer, sched: &mut dyn event::Scheduler) {
            static mut STOP: i32 = 0;
            if unsafe { STOP } == 0 {
                unsafe { STOP = 1 };
                unsafe { sched.set_timer(this, 1000000) };
            } else {
                sched.stop();
            }
        }
        let timer = event::Timer::new(timer_timeout);
        let now = sched.now();
        unsafe { sched.set_timer(&timer, 1 * 1000 * 1000) };
        sched.run();
        let cur = sched.now();
        assert!((cur - now).as_micros() >= 2 * 1000 * 1000);
    }
}
